#include "stdafx.h"
#include "RealICollection.h"
#include "PortList.h"
#include "NetCardList.h"
#include "RealIExample.h"

ITypeInfo *ExampleTypeInfo;

HRESULT LoadExampleTypeInfo()
{
    HRESULT hr;
    ITypeLib *pTypeLib = NULL;
    hr = LoadRegTypeLib(TLBID_IExample, 1, 0, 0, &pTypeLib);
    if (FAILED(hr)) return hr;
    hr = pTypeLib->GetTypeInfoOfGuid(IID_IExample, &ExampleTypeInfo);
    pTypeLib->Release();
    if (FAILED(hr)) return hr;
    ExampleTypeInfo->AddRef();
    return S_OK;
}

RealIExample::RealIExample() : m_count(1), m_str(NULL)
{
}

RealIExample::~RealIExample()
{
    SysFreeString(m_str);
}

HRESULT STDMETHODCALLTYPE RealIExample::QueryInterface(REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, IID_IExample) ||
        IsEqualIID(riid, IID_IUnknown) ||
        IsEqualIID(riid, IID_IDispatch))
    {
        *ppv = this;
        AddRef();
        return S_OK;
    }

    *ppv = NULL;
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE RealIExample::AddRef()
{
    return ++m_count;
}

ULONG STDMETHODCALLTYPE RealIExample::Release()
{
    if (--m_count == 0)
    {
        delete this;
        InterlockedDecrement(&OutstandingObjects);
        return 0;
    }
    return m_count;
}

HRESULT STDMETHODCALLTYPE RealIExample::SetString(BSTR str)
{
    if (str == NULL) return E_POINTER;
    if (m_str) SysFreeString(m_str);
    m_str = SysAllocStringLen(str, SysStringLen(str));
    if (m_str == NULL) return E_OUTOFMEMORY;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExample::GetString(BSTR *str)
{
    if (str == NULL) return E_POINTER;
    *str = SysAllocStringLen(m_str, SysStringLen(m_str));
    if (*str == NULL) return E_OUTOFMEMORY;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExample::GetTypeInfoCount(UINT *pctinfo)
{
    *pctinfo = 1;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExample::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
    *ppTInfo = NULL;
    if (iTInfo != 0) return DISP_E_BADINDEX;
    if (ExampleTypeInfo != NULL)
    {
        ExampleTypeInfo->AddRef();
    }
    else
    {
        HRESULT hr = LoadExampleTypeInfo();
        if (FAILED(hr)) return hr;
    }
    *ppTInfo = ExampleTypeInfo;
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExample::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
    if (ExampleTypeInfo == NULL)
    {
        HRESULT hr = LoadExampleTypeInfo();
        if (FAILED(hr)) return hr;
    }
    return DispGetIDsOfNames(ExampleTypeInfo, rgszNames, cNames, rgDispId);
}

HRESULT STDMETHODCALLTYPE RealIExample::Invoke(DISPID dispIdMember, REFIID riid,
                                               LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
                                               VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
    if (!IsEqualIID(riid, IID_NULL)) return DISP_E_UNKNOWNINTERFACE;
    if (ExampleTypeInfo == NULL)
    {
        HRESULT hr = LoadExampleTypeInfo();
        if (FAILED(hr)) return hr;
    }
    return DispInvoke(this, ExampleTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}

HRESULT STDMETHODCALLTYPE RealIExample::GetPorts(IDispatch **pObj)
{
    *pObj = new RealICollection(&PortList);
    if (*pObj == NULL) return E_OUTOFMEMORY;
    InterlockedIncrement(&OutstandingObjects);
    return S_OK;
}

HRESULT STDMETHODCALLTYPE RealIExample::GetNetCards(IDispatch **pObj)
{
    *pObj = new RealICollection(&NetCardList);
    if (*pObj == NULL) return E_OUTOFMEMORY;
    InterlockedIncrement(&OutstandingObjects);
    return S_OK;
}
